import { 
  ProxyRule, 
  InsertProxyRule, 
  BackendServer, 
  InsertBackendServer,
  SystemMetrics,
  InsertSystemMetrics,
  ProxyLog,
  InsertProxyLog,
  User,
  InsertUser
} from "@shared/schema";

export interface IStorage {
  // User methods
  getUser(id: number): Promise<User | undefined>;
  getUserByUsername(username: string): Promise<User | undefined>;
  createUser(user: InsertUser): Promise<User>;

  // Proxy rule methods
  getProxyRules(): Promise<ProxyRule[]>;
  getProxyRule(id: number): Promise<ProxyRule | undefined>;
  createProxyRule(rule: InsertProxyRule): Promise<ProxyRule>;
  updateProxyRule(id: number, rule: Partial<InsertProxyRule>): Promise<ProxyRule | undefined>;
  deleteProxyRule(id: number): Promise<boolean>;

  // Backend server methods
  getBackendServers(proxyRuleId?: number): Promise<BackendServer[]>;
  getBackendServer(id: number): Promise<BackendServer | undefined>;
  createBackendServer(server: InsertBackendServer): Promise<BackendServer>;
  updateBackendServer(id: number, server: Partial<InsertBackendServer>): Promise<BackendServer | undefined>;
  deleteBackendServer(id: number): Promise<boolean>;

  // System metrics methods
  getLatestSystemMetrics(): Promise<SystemMetrics | undefined>;
  createSystemMetrics(metrics: InsertSystemMetrics): Promise<SystemMetrics>;
  getSystemMetricsHistory(limit?: number): Promise<SystemMetrics[]>;

  // Proxy logs methods
  getProxyLogs(limit?: number, proxyRuleId?: number): Promise<ProxyLog[]>;
  createProxyLog(log: InsertProxyLog): Promise<ProxyLog>;
  clearProxyLogs(olderThan?: Date): Promise<number>;
}

export class MemStorage implements IStorage {
  private users: Map<number, User>;
  private proxyRules: Map<number, ProxyRule>;
  private backendServers: Map<number, BackendServer>;
  private systemMetrics: SystemMetrics[];
  private proxyLogs: ProxyLog[];
  private currentUserId: number;
  private currentProxyRuleId: number;
  private currentBackendServerId: number;
  private currentSystemMetricsId: number;
  private currentProxyLogId: number;

  constructor() {
    this.users = new Map();
    this.proxyRules = new Map();
    this.backendServers = new Map();
    this.systemMetrics = [];
    this.proxyLogs = [];
    this.currentUserId = 1;
    this.currentProxyRuleId = 1;
    this.currentBackendServerId = 1;
    this.currentSystemMetricsId = 1;
    this.currentProxyLogId = 1;
  }

  // User methods
  async getUser(id: number): Promise<User | undefined> {
    return this.users.get(id);
  }

  async getUserByUsername(username: string): Promise<User | undefined> {
    return Array.from(this.users.values()).find(user => user.username === username);
  }

  async createUser(insertUser: InsertUser): Promise<User> {
    const id = this.currentUserId++;
    const user: User = { ...insertUser, id };
    this.users.set(id, user);
    return user;
  }

  // Proxy rule methods
  async getProxyRules(): Promise<ProxyRule[]> {
    return Array.from(this.proxyRules.values());
  }

  async getProxyRule(id: number): Promise<ProxyRule | undefined> {
    return this.proxyRules.get(id);
  }

  async createProxyRule(insertRule: InsertProxyRule): Promise<ProxyRule> {
    const id = this.currentProxyRuleId++;
    const now = new Date();
    const rule: ProxyRule = {
      ...insertRule,
      id,
      description: insertRule.description || null,
      targetHost: insertRule.targetHost || "localhost",
      status: insertRule.status || "stopped",
      loadBalancing: insertRule.loadBalancing || "round-robin",
      healthCheck: insertRule.healthCheck ?? true,
      createdAt: now,
      updatedAt: now,
    };
    this.proxyRules.set(id, rule);
    return rule;
  }

  async updateProxyRule(id: number, updateData: Partial<InsertProxyRule>): Promise<ProxyRule | undefined> {
    const existing = this.proxyRules.get(id);
    if (!existing) return undefined;

    const updated: ProxyRule = {
      ...existing,
      ...updateData,
      updatedAt: new Date(),
    };
    this.proxyRules.set(id, updated);
    return updated;
  }

  async deleteProxyRule(id: number): Promise<boolean> {
    return this.proxyRules.delete(id);
  }

  // Backend server methods
  async getBackendServers(proxyRuleId?: number): Promise<BackendServer[]> {
    const servers = Array.from(this.backendServers.values());
    return proxyRuleId ? servers.filter(s => s.proxyRuleId === proxyRuleId) : servers;
  }

  async getBackendServer(id: number): Promise<BackendServer | undefined> {
    return this.backendServers.get(id);
  }

  async createBackendServer(insertServer: InsertBackendServer): Promise<BackendServer> {
    const id = this.currentBackendServerId++;
    const server: BackendServer = {
      ...insertServer,
      id,
      status: insertServer.status || "healthy",
      weight: insertServer.weight || 1,
      responseTime: insertServer.responseTime || 0,
      createdAt: new Date(),
      lastHealthCheck: null,
    };
    this.backendServers.set(id, server);
    return server;
  }

  async updateBackendServer(id: number, updateData: Partial<InsertBackendServer>): Promise<BackendServer | undefined> {
    const existing = this.backendServers.get(id);
    if (!existing) return undefined;

    const updated: BackendServer = {
      ...existing,
      ...updateData,
    };
    this.backendServers.set(id, updated);
    return updated;
  }

  async deleteBackendServer(id: number): Promise<boolean> {
    return this.backendServers.delete(id);
  }

  // System metrics methods
  async getLatestSystemMetrics(): Promise<SystemMetrics | undefined> {
    return this.systemMetrics[this.systemMetrics.length - 1];
  }

  async createSystemMetrics(insertMetrics: InsertSystemMetrics): Promise<SystemMetrics> {
    const id = this.currentSystemMetricsId++;
    const metrics: SystemMetrics = {
      ...insertMetrics,
      id,
      timestamp: new Date(),
    };
    this.systemMetrics.push(metrics);
    
    // Keep only last 1000 metrics
    if (this.systemMetrics.length > 1000) {
      this.systemMetrics = this.systemMetrics.slice(-1000);
    }
    
    return metrics;
  }

  async getSystemMetricsHistory(limit: number = 100): Promise<SystemMetrics[]> {
    return this.systemMetrics.slice(-limit);
  }

  // Proxy logs methods
  async getProxyLogs(limit: number = 100, proxyRuleId?: number): Promise<ProxyLog[]> {
    let logs = [...this.proxyLogs];
    
    if (proxyRuleId) {
      logs = logs.filter(log => log.proxyRuleId === proxyRuleId);
    }
    
    return logs.slice(-limit).reverse();
  }

  async createProxyLog(insertLog: InsertProxyLog): Promise<ProxyLog> {
    const id = this.currentProxyLogId++;
    const log: ProxyLog = {
      ...insertLog,
      id,
      proxyRuleId: insertLog.proxyRuleId || null,
      metadata: insertLog.metadata || null,
      timestamp: new Date(),
    };
    this.proxyLogs.push(log);
    
    // Keep only last 10000 logs
    if (this.proxyLogs.length > 10000) {
      this.proxyLogs = this.proxyLogs.slice(-10000);
    }
    
    return log;
  }

  async clearProxyLogs(olderThan?: Date): Promise<number> {
    const originalLength = this.proxyLogs.length;
    
    if (olderThan) {
      this.proxyLogs = this.proxyLogs.filter(log => log.timestamp > olderThan);
    } else {
      this.proxyLogs = [];
    }
    
    return originalLength - this.proxyLogs.length;
  }
}

export const storage = new MemStorage();
